package com.bom.boot.easy.facade.dto;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.bom.boot.easy.controller.exception.InException;
import com.bom.boot.easy.entity.OptionInEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.log4j.Log4j2;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

import java.sql.Timestamp;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 查询参数
 */
@EqualsAndHashCode(callSuper = true)
@Data
@Log4j2
public class BaseDTO extends LinkedHashMap<String, Object> {
    private ExpressionParser expressionParser;

    public <T> T get(String key, Class<T> type) {
        return MapUtil.get(this, key, type);
    }

    public BaseDTO() {
        this.expressionParser = new SpelExpressionParser();
    }

    public void validFormat(OptionInEntity optionIn, Map<String, String> elMap) {
        this.put("this", optionIn);
        String validJson = optionIn.getValid();
        if (StrUtil.isNotBlank(validJson)) {
            List<Valid> valids = JSONUtil.parseArray(validJson).toList(Valid.class);
            for (Valid valid : valids) {
                if (valid != null) {
                    String el = valid.getEl();
                    if (StrUtil.isNotBlank(el)) {
                        Boolean elFlag = getRs(el, elMap, Boolean.class);
                        if (elFlag) {
                            String msg = getRs(valid.getMsg(), elMap, String.class);
                            log.warn(msg);
                            throw new InException(this, msg);
                        }
                    }
                }
            }
        }
        this.remove("this");

        String format = optionIn.getFormat();
        if (StrUtil.isNotBlank(format)) {
            Object rs = formatEl(format, elMap);
            if (this.containsKey(optionIn.getId().getName())) {
                this.put(optionIn.getId().getName(), rs);
            }
            if (StrUtil.isNotBlank(optionIn.getAlias())) {
                this.put(optionIn.getAlias(), rs);
            }
        }
    }

    @Data
    public static class Valid {
        private String el;
        private String msg;
    }

    @SafeVarargs
    public final <T> T getRs(String el, Map<String, String> elMap, Class<T>... tClass) {
        List<String> keys = ReUtil.findAllGroup1("T\\(([a-zA-Z]+)\\)", el);
        for (String key : keys) {
            if (elMap.containsKey(key)) {
                el = ReUtil.replaceAll(el, "T\\(" + key + "\\)", "T(" + elMap.get(key) + ")");
            }
        }
        el = StrUtil.emptyToDefault(ReUtil.replaceAll(el, "#([_a-zA-Z]+)", "#root.get('$1')"), el);
        Expression expression = expressionParser.parseExpression(el);
        return expression.getValue(this, tClass[0]);
    }

    public final Object formatEl(String el, Map<String, String> elMap) {
        return formatEl(el, elMap, this);
    }

    public final Object formatEl(String el, Map<String, String> elMap, Map<String, Object> root) {
        List<String> keys = ReUtil.findAllGroup1("T\\(([a-zA-Z]+)\\)", el);
        for (String key : keys) {
            if (elMap.containsKey(key)) {
                el = ReUtil.replaceAll(el, "T\\(" + key + "\\)", "T(" + elMap.get(key) + ")");
            }
        }
        el = StrUtil.emptyToDefault(ReUtil.replaceAll(el, "#([_a-zA-Z]+)", "#root.get('$1')"), el);
        Expression expression = expressionParser.parseExpression(el);
        return expression.getValue(root);
    }
}
